﻿using System;
using System.Web;
using System.Web.Mvc;
using System.Collections.Generic;

using UncleBobWebService.Models;
using UncleBobWebService.ServiceRequester;


namespace UncleBobApplicantWebService.Controllers
{
    public class ApplicantApplyController : Controller
    {
        private UncleBobApplicantWebService.ApplicantWebService.WebServiceClient m_applicantClient =
            new UncleBobApplicantWebService.ApplicantWebService.WebServiceClient();

        /*
         * NextQuestion() : ActionResult
         * ------------------------------------------------------------------------
         * NextQuestion will determine whether the next question is MultipleChoice
         * or Extended, and will redirect to the appropriate handler accordingly.
         */
        public ActionResult NextQuestion()
        {
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;

            if (questions == null)
            {
                TempData[SessionKeys.ERROR] = "Could not retrieve Application Questions from the database.";
                return RedirectToAction("Error", "Error");
            }
            else if (questions.Questions[questions.CurrentQuestion] is MultipleChoiceQuestion)
            {
                return RedirectToAction("MultipleChoiceQuestion", "ApplicantApply");
            }
            else
            {
                return RedirectToAction("ExtendedQuestion", "ApplicantApply");
            }
        }

        /*
         * EvaluateApplication() : ActionResult
         * ------------------------------------------------------------------------
         * EvaluateAction will process flow of control when all Questions have been
         * answered. It will evaluate all of the applicant's responses to the the
         * questions and determine whether the MC questions are all correct. If not,
         * it will refuse submission. Otherwise, it will submit the application to
         * the database.
         */
        public ActionResult EvaluateApplication()
        {
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;
            
            bool isAccepted = true;
            bool isFinished = false;
            
            // iterate over all questions for processing
            for (int i = 0; i < questions.Questions.Count && !isFinished; ++i)
            {
                // if you encounter a MultipleChoiceQuestion, we want to process the Applicant's answers
                if (questions.Questions[i] is MultipleChoiceQuestion)
                {
                    MultipleChoiceQuestion q = questions.Questions[i] as MultipleChoiceQuestion;

                    foreach (KeyValuePair<int, Answer> answer in q.PossibleAnswers)
                    {
                        // if the applicant's selected answer is incorrect, we reject the application
                        if (answer.Value.IsSelected)                        
                        {
                            if (!answer.Value.IsCorrect)
                            {
                                isAccepted = false;
                                isFinished = true;
                                break;
                            }
                        }
                    }
                }
            }

            //
            // Generate the appropriate message after determining whether the application
            // has been accepted or not.
            //
            string resultMessage = string.Empty;

            if (!isAccepted)
            {
                resultMessage = "We're sorry. You do not meet the minimum requirements. Please try again at a later date.";
            }
            else
            {
                // Attempt to add the application to the Database, throw an error if not successful.
                if ( !InsertApplicationToDatabase() )
                {
                    TempData[SessionKeys.ERROR] = "Database Error: Could not save application to Database";
                    return RedirectToAction("Error", "Error");
                }

                resultMessage = "Thank you! Your application has been submitted successfully.";
            }

            ViewData.Model = resultMessage;
            return View();
        }

        /*
         * PreviewApplication() : ActionResult
         * ------------------------------------------------------------------------
         * Method will allow the applicant to preview their answers to the given
         * questions before submitting application.
         */
        [SessionExpiredFilter]
        public ActionResult PreviewApplication()
        {
            Dictionary<string, string> questionsAndAnswers = new Dictionary<string, string>();
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;

            //
            // Iterate over questions and add each question and its corresponding answer to 
            // the Dictionary as a Key-Value pair.
            //
            foreach (ApplicationQuestion question in questions.Questions)
            {
                if (question is MultipleChoiceQuestion)
                {
                    MultipleChoiceQuestion mc = question as MultipleChoiceQuestion;
                    string answer = string.Empty;

                    foreach (KeyValuePair<int, Answer> a in mc.PossibleAnswers)
                    {
                        // The selected answer is the one we want to add
                        if (a.Value.IsSelected)
                        {
                            answer = a.Value.TheAnswer;
                            break;
                        }
                    }

                    questionsAndAnswers.Add(mc.Question, answer);
                }
                else
                {
                    ExtendedQuestion eq = question as ExtendedQuestion;
                    questionsAndAnswers.Add(eq.Question, eq.Response);
                }
            }

            // send the dictionary to the view for display
            return View(questionsAndAnswers);
        }

        /*
         * MultipleChoiceQuestion() : ActionResult
         * ------------------------------------------------------------------------
         * The handler will pass the current question to the MultipleChoiceQuestion
         * view.
         */
        public ActionResult MultipleChoiceQuestion()
        {
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;
            MultipleChoiceQuestion question = questions.Questions[questions.CurrentQuestion] as MultipleChoiceQuestion;
            question.RuntimeCount = questions.CurrentQuestion;

            return View(question);
        }

        /*
         * ExtendedQuestion() : ActionResult
         * ------------------------------------------------------------------------
         * The handler will pass the current question to the ExtendedQuestion view.
         */
        public ActionResult ExtendedQuestion()
        {
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;
            ExtendedQuestion question = questions.Questions[questions.CurrentQuestion] as ExtendedQuestion;
            question.RuntimeCount = questions.CurrentQuestion;

            return View(question);
        }

        /*
         * FormAction() : ActionResult
         * ------------------------------------------------------------------------
         * FormAction will process the FormCollection returned by the View and then
         * redirect to the NextQuestion if there are more questions. Otherwise,
         * redirect to EvaluateApplication method.
         */
        [SessionExpiredFilter]
        public ActionResult FormAction(FormCollection collection)
        {
            // Go back to applicant main if user is finished
            if (null != collection["applicantmain"] || null != collection["previewcancel"])
            {
                return RedirectToAction("MainMenu", "ApplicantMainMenu");
            }

            // From preview, go back to the last question
            if (null != collection["previewback"])
            {
                return RedirectToAction("NextQuestion", "ApplicantApply");
            }

            // From preview, go to the Application evaluation View
            if (null != collection["previewsubmit"])
            {
                return RedirectToAction("EvaluateApplication", "ApplicantApply");
            }

            // otherwise, continue with application main flow
            return ApplicationMainFlow(collection);
        }

        /*
         * ApplicationMainFlow() : ActionResult
         * ----------------------------------------------------------------
         * This method processes the flow between each question, and will
         * enable the user to go to either the "next" or "previous" question.
         */
        private ActionResult ApplicationMainFlow(FormCollection collection)
        {
            ApplicationQuestions questions = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;

            // Record the applicant's answers for the current question
            if (questions.Questions[questions.CurrentQuestion] is MultipleChoiceQuestion)
            {
                ProcessAnswers(questions.Questions[questions.CurrentQuestion]
                    as MultipleChoiceQuestion, collection);
            }
            else
            {
                ExtendedQuestion question = questions.Questions[questions.CurrentQuestion] as ExtendedQuestion;
                question.Response = collection["answer"];
            }

            // If the applicant hit the previous button, go to the previous question
            if (null != collection["previous"])
            {
                --questions.CurrentQuestion;
            }

            //
            // If there are still more questions to go through, process the next question.
            // Otherwise, go to application preview.
            //
            if (questions.CurrentQuestion < (questions.TotalQuestions - 1))
            {
                if (null != collection["next"])
                {
                    ++questions.CurrentQuestion;
                }

                return RedirectToAction("NextQuestion", "ApplicantApply");
            }
            else
            {
                return RedirectToAction("PreviewApplication", "ApplicantApply");
            }
        }

        /*
         * ProcessAnswers() : void
         * ---------------------------------------------------------------------
         * Determine which question the applicant marked as the correct response
         * and save or later processing
         */
        private void ProcessAnswers(MultipleChoiceQuestion question, FormCollection collection)
        {
            int count = 0;

            // Iterate over each item in the sorted dictionary until you find the
            // answer which the user has selected.
            foreach (KeyValuePair<int, Answer> answer in question.PossibleAnswers)
            {
                string index = Convert.ToString(count);

                if (collection["answer"] == index)
                {
                    answer.Value.IsSelected = true;
                }
                else
                {
                    answer.Value.IsSelected = false;
                }

                ++count;
            }
        }

        /*
         * InsertApplicationToDatabase() : void
         * -------------------------------------------------------------------------
         * Upon successful evaluation, the user's Registration info, their answers to
         * the Application Questions and the time of submission will stored in the
         * database.
         */
        private bool InsertApplicationToDatabase()
        {
            // Grab the user's existing registration
            RegisterModel registration = Session[SessionKeys.USER] as RegisterModel;
            JobApplication jobApp = new JobApplication();

            //
            // set the job application date, retrieve the job from the session, and record the
            // associated answers for that job.
            //
            jobApp.ApplyDate = System.DateTime.Now;
            jobApp.Job = Session[SessionKeys.JOB] as JobModel;
            jobApp.Job.QuestionsList = Session[SessionKeys.QUESTIONS] as ApplicationQuestions;
            jobApp.UserID = registration.UserID;

            // create the correct message type and send the data to the DB
            Message msg = new Message(MessageTypes.SERVICE_SAVE_JOB_APPLICATION);
            msg.Data = jobApp;
            msg = m_applicantClient.RequestService(msg);

            return msg.Result;
        }
    }
}
